package com.sugar.follow.up.module.business.service.user;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.sugar.follow.up.framework.common.pojo.PageParam;
import com.sugar.follow.up.framework.common.pojo.PageResult;
import com.sugar.follow.up.framework.common.util.object.BeanUtils;
import com.sugar.follow.up.module.business.controller.admin.user.vo.BizUserPageReqVO;
import com.sugar.follow.up.module.business.controller.admin.user.vo.BizUserPatientSimpleRespVO;
import com.sugar.follow.up.module.business.controller.admin.user.vo.BizUserSaveReqVO;
import com.sugar.follow.up.module.business.controller.app.record.vo.AppRecordAnswerReqVO;
import com.sugar.follow.up.module.business.controller.app.record.vo.AppRecordDetailRespVO;
import com.sugar.follow.up.module.business.controller.app.record.vo.AppRecordPageRespVO;
import com.sugar.follow.up.module.business.controller.app.record.vo.AppRecordRespVO;
import com.sugar.follow.up.module.business.controller.app.user.vo.AppBizUserLoginReqVO;
import com.sugar.follow.up.module.business.controller.app.user.vo.AppBizUserRespVO;
import com.sugar.follow.up.module.business.controller.app.user.vo.AppBizUserUpdateReqVO;
import com.sugar.follow.up.module.business.dal.dataobject.followupquestionrecord.FollowUpQuestionRecordDO;
import com.sugar.follow.up.module.business.dal.dataobject.followuprecord.FollowUpRecordDO;
import com.sugar.follow.up.module.business.dal.dataobject.questionnairequestionrecord.QuestionnaireQuestionRecordDO;
import com.sugar.follow.up.module.business.dal.dataobject.questionnairerecord.QuestionnaireRecordDO;
import com.sugar.follow.up.module.business.dal.dataobject.user.BizUserDO;
import com.sugar.follow.up.module.business.dal.dataobject.userpatient.UserPatientDO;
import com.sugar.follow.up.module.business.dal.mysql.followupquestionrecord.FollowUpQuestionRecordMapper;
import com.sugar.follow.up.module.business.dal.mysql.followuprecord.FollowUpRecordMapper;
import com.sugar.follow.up.module.business.dal.mysql.questionnairequestionrecord.QuestionnaireQuestionRecordMapper;
import com.sugar.follow.up.module.business.dal.mysql.questionnairerecord.QuestionnaireRecordMapper;
import com.sugar.follow.up.module.business.dal.mysql.user.BizUserMapper;
import com.sugar.follow.up.module.business.dal.mysql.userpatient.UserPatientMapper;
import com.sugar.follow.up.module.business.enums.config.ConfigEnum;
import com.sugar.follow.up.module.business.service.config.BizConfigService;
import com.sugar.follow.up.module.business.util.AdminUserUtil;
import com.sugar.follow.up.module.business.util.wechat.WeChatLoginUtil;
import com.sugar.follow.up.module.business.util.wechat.vo.WeChatOpenIdRespVO;
import com.sugar.follow.up.module.system.api.auth.AuthApi;
import com.sugar.follow.up.module.system.api.auth.dto.AppAuthDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import static com.sugar.follow.up.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.sugar.follow.up.module.business.enums.ErrorCodeConstants.*;

/**
 * 用户 Service 实现类
 *
 * @author Ysugar
 */
@Slf4j
@Service
@Validated
public class BizUserServiceImpl implements BizUserService {

    @Resource
    private BizUserMapper bizUserMapper;
    @Resource
    private UserPatientMapper userPatientMapper;

    @Resource
    private FollowUpRecordMapper followUpRecordMapper;
    @Resource
    private FollowUpQuestionRecordMapper followUpQuestionRecordMapper;
    @Resource
    private QuestionnaireRecordMapper questionnaireRecordMapper;
    @Resource
    private QuestionnaireQuestionRecordMapper questionnaireQuestionRecordMapper;

    @Resource
    private BizConfigService configService;
    @Resource
    private AuthApi authApi;

    private static final ReentrantLock LOGIN_LOCK = new ReentrantLock();

    @Override
    public Long createBizUser(BizUserSaveReqVO createReqVO) {
        // 插入
        BizUserDO bizUser = BeanUtils.toBean(createReqVO, BizUserDO.class);
        bizUserMapper.insert(bizUser);

        // 返回
        return bizUser.getId();
    }

    @Override
    public void updateBizUser(BizUserSaveReqVO updateReqVO) {
        // 校验存在
        validateBizUserExists(updateReqVO.getId());
        // 更新
        BizUserDO updateObj = BeanUtils.toBean(updateReqVO, BizUserDO.class);
        bizUserMapper.updateById(updateObj);
    }

    @Override
    public void deleteBizUser(Long id) {
        // 校验存在
        validateBizUserExists(id);
        // 删除
        bizUserMapper.deleteById(id);
    }

    @Override
    public void deleteBizUserListByIds(List<Long> ids) {
        // 删除
        bizUserMapper.deleteByIds(ids);
    }


    private void validateBizUserExists(Long id) {
        if (bizUserMapper.selectById(id) == null) {
            throw exception(BIZ_USER_NOT_EXISTS);
        }
    }

    @Override
    public BizUserDO getBizUser(Long id) {
        return bizUserMapper.selectById(id);
    }

    @Override
    public PageResult<BizUserDO> getBizUserPage(BizUserPageReqVO pageReqVO) {
        return bizUserMapper.selectPage(pageReqVO);
    }

    @Override
    public List<BizUserPatientSimpleRespVO> getBizUserAndPatientTree() {
        // 获取后台用户ID
        Long doctorId = AdminUserUtil.isSuperAdmin();

        List<BizUserPatientSimpleRespVO> userList = BeanUtils.toBean(bizUserMapper.selectList(), BizUserPatientSimpleRespVO.class,
                o -> o.setName(o.getNickname()));
        userList.forEach(
                user -> user.setChildren(
                        BeanUtils.toBean(userPatientMapper.selectList(UserPatientDO::getUserId, user.getId(), UserPatientDO::getDoctorId, doctorId),
                                BizUserPatientSimpleRespVO.class)));

        return userList.stream().filter(o -> CollUtil.isNotEmpty(o.getChildren())).collect(Collectors.toList());
    }

    @Override
    public AppAuthDTO login(AppBizUserLoginReqVO loginReqVO) {
        WeChatOpenIdRespVO weChatOpenIdRespVO = WeChatLoginUtil.wechatLogin(loginReqVO.getCode());
        log.info("微信登录返回：{}", JSONUtil.toJsonStr(weChatOpenIdRespVO));
        if (Objects.isNull(weChatOpenIdRespVO) || StrUtil.isBlank(weChatOpenIdRespVO.getOpenId()))
            throw exception(WE_CHAT_MOBILE_AUTH_ERROR);
        // 根据手机号code换取手机号
        String userMobile = WeChatLoginUtil.getUserMobile(loginReqVO.getMobileCode());
        if (StrUtil.isBlank(userMobile))
            throw exception(WE_CHAT_MOBILE_AUTH_ERROR);

        // 根据 手机号 查询用户信息
        BizUserDO user = bizUserMapper.selectOne(BizUserDO::getMobile, userMobile);

        if (Objects.isNull(user)) {
            LOGIN_LOCK.lock();
            try {
                // 再次查询
                user = bizUserMapper.selectOne(BizUserDO::getMobile, userMobile);
                if (Objects.isNull(user)) {
                    // 获取默认头像
                    String avatar = configService.getBizConfigByKey(ConfigEnum.USER_DEFAULT_AVATAR, String.class);

                    user = new BizUserDO();
                    user.setMobile(userMobile)
                            .setNickname(userMobile)
                            // 设置默认头像
                            .setAvatar(avatar)
                            .setLastLoginTime(LocalDateTime.now())
                            .setOpenid(weChatOpenIdRespVO.getUnionId());

                    if (bizUserMapper.insert(user) <= 0)
                        throw exception(BIZ_USER_REGISTER_ERROR);
                }
            } catch (Throwable e) {
                log.error("用户注册失败：", e);
            } finally {
                if (LOGIN_LOCK.isLocked())
                    LOGIN_LOCK.unlock();
            }
        } else if (!user.getStatus())
            throw exception(USER_ACCOUNT_FORBIDDEN);
        else
            // 更新用户最后一次登录时间
            bizUserMapper.update(BizUserDO::getId, user.getId(), BizUserDO::getLastLoginTime, LocalDateTime.now());

        AppAuthDTO appAuthDTO = authApi.appLogin(user.getId(), user.getMobile());

        appAuthDTO.setUserInfo(BeanUtils.toBean(user, AppBizUserRespVO.class));
        return appAuthDTO;
    }

    @Override
    public void appUpdateBizUser(AppBizUserUpdateReqVO updateReqVO, Long userId) {
        String avatar = updateReqVO.getAvatar();
        String nickname = updateReqVO.getNickname();

        if (StrUtil.isNotBlank(avatar) || StrUtil.isNotBlank(nickname))
            bizUserMapper.update(BizUserDO::getId, userId, BizUserDO::getAvatar, avatar, BizUserDO::getNickname, nickname);
    }

    @Override
    public List<AppRecordRespVO> getRecordAll(Integer count, Long userId) {
        return bizUserMapper.getRecordAll(count, userId);
    }


    @Override
    public AppRecordDetailRespVO getRecordDetail(Long id, Integer type) {
        AppRecordDetailRespVO respVO = BeanUtils.toBean(
                type.equals(1) ? questionnaireRecordMapper.selectById(id) : followUpRecordMapper.selectById(id),
                AppRecordDetailRespVO.class);

        // 获取题目
        if (Objects.nonNull(respVO)) {
            if (type.equals(1))
                respVO.setQuestions(BeanUtils.toBean(questionnaireQuestionRecordMapper.selectList(QuestionnaireQuestionRecordDO::getRecordId, id),
                        AppRecordDetailRespVO.QuestionRespVO.class));
            else
                respVO.setQuestions(BeanUtils.toBean(followUpQuestionRecordMapper.selectList(FollowUpQuestionRecordDO::getRecordId, id),
                        AppRecordDetailRespVO.QuestionRespVO.class));
        }

        return respVO;
    }

    @Override
    public PageResult<AppRecordPageRespVO> getRecordPage(PageParam pageParam, Long userId) {

        Long recordPageCount = bizUserMapper.getRecordPageCount(userId);
        if (recordPageCount > 0) {
            Integer pageNo = pageParam.getPageNo();
            Integer pageSize = pageParam.getPageSize();

            int skipCount = (pageNo - 1) * pageSize;

            List<AppRecordPageRespVO> recordList = bizUserMapper.getRecordPage(userId, skipCount, pageSize);

            return new PageResult<>(recordList, recordPageCount);
        }
        return new PageResult<>(Collections.emptyList(), 0L);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void answerQuestion(AppRecordAnswerReqVO reqVO, Long userId) {
        Integer type = reqVO.getType();
        List<AppRecordAnswerReqVO.Question> questions = reqVO.getQuestions();

        Long recordId = null;

        for (AppRecordAnswerReqVO.Question question : questions) {
            Long questionId = question.getQuestionId();
            // 更新问卷答案
            if (type.equals(1)) {
                QuestionnaireQuestionRecordDO questionRecordDO = questionnaireQuestionRecordMapper.selectById(questionId);
                if (Objects.nonNull(questionRecordDO)) {
                    questionnaireQuestionRecordMapper.update(QuestionnaireQuestionRecordDO::getId, questionId,
                            QuestionnaireQuestionRecordDO::getAnswer, question.getAnswer());
                    recordId = questionRecordDO.getRecordId();
                }
            } else {  // 更新随访答案
                FollowUpQuestionRecordDO questionRecordDO = followUpQuestionRecordMapper.selectById(questionId);
                if (Objects.nonNull(questionRecordDO)) {
                    followUpQuestionRecordMapper.update(FollowUpQuestionRecordDO::getId, questionId,
                            FollowUpQuestionRecordDO::getAnswer, question.getAnswer());
                    recordId = questionRecordDO.getRecordId();
                }
            }
        }

        // 判断是否还有未完成的题目
        if (type.equals(1)) {
            Long count = questionnaireQuestionRecordMapper.selectCount(Wrappers.<QuestionnaireQuestionRecordDO>lambdaQuery()
                    .eq(QuestionnaireQuestionRecordDO::getRecordId, recordId)
                    .isNull(QuestionnaireQuestionRecordDO::getAnswer));

            // 为 0 则全部答完，更新完成状态
            if (count == 0)
                questionnaireRecordMapper.update(QuestionnaireRecordDO::getId, recordId,
                        QuestionnaireRecordDO::getIsDone, 1, QuestionnaireRecordDO::getDoneTime, LocalDateTime.now());
        } else {
            Long count = followUpQuestionRecordMapper.selectCount(Wrappers.<FollowUpQuestionRecordDO>lambdaQuery()
                    .eq(FollowUpQuestionRecordDO::getRecordId, recordId)
                    .isNull(FollowUpQuestionRecordDO::getAnswer));

            // 为 0 则全部答完，更新完成状态
            if (count == 0)
                followUpRecordMapper.update(FollowUpRecordDO::getId, recordId,
                        FollowUpRecordDO::getIsDone, 1, FollowUpRecordDO::getDoneTime, LocalDateTime.now());
        }
    }

    @Override
    public void updateLike(String unionId, String openid, boolean isLike) {
        if (isLike)
            bizUserMapper.update(BizUserDO::getOpenid, unionId, BizUserDO::getGzOpenid, openid, BizUserDO::getIsFollow, true);
        else
            bizUserMapper.update(BizUserDO::getGzOpenid, openid, BizUserDO::getIsFollow, false);
    }
}